package fractal;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

/**
 * Created by IntelliJ IDEA.
 * User: ilya
 * Date: 24.09.11
 * Time: 16:41
 */
public class FractalView extends JPanel implements MouseListener, MouseMotionListener {

    public static final int MOVE = 1;
    public static final int ZOOM_IN = 2;
    public static final int ZOOM_OUT = 3;

    private Fractal fractal;
    private Palette palette;
    private Coordinates coordinates;
    private int mouseMode = MOVE;
    private BufferedImage buffer;

    public FractalView(Fractal fractal, Coordinates coordinates) {
        this.fractal = fractal;
        this.coordinates = coordinates;
        this.palette = new GrayPalette();

        addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                updateBuffer();
            }
        });

        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public Fractal getFractal() {
        return fractal;
    }

    public void setFractal(Fractal fractal) {
        this.fractal = fractal;
        updateBuffer();
    }

    public Palette getPalette() {
        return palette;
    }

    public void setPalette(Palette palette) {
        this.palette = palette;
//        updateBuffer();
    }

    public Coordinates getCoordinates() {
        return coordinates;
    }

    public void setCoordinates(Coordinates coordinates) {
        this.coordinates = coordinates;
        updateBuffer();
    }

    public int getMouseMode() {
        return mouseMode;
    }

    public void setMouseMode(int mouseMode) {
        this.mouseMode = mouseMode;
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
        if (down) {
            g.setColor(Color.BLACK);
            g.drawRect(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
        }
    }

    private void updateBuffer() {
        int height = getHeight();
        int width = getWidth();
        buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        double x0 = coordinates.getX0();
        double y0 = coordinates.getY0();
        double m = coordinates.getM();

        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                int in = fractal.isIn(x0 + m * x, y0 + m * y);
                buffer.setRGB(x, y, in);
//                buffer.setRGB(x, y, palette.getColor(in).getRGB());
            }

        BufferedImage blurred = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++) {
                if (x == 0 || x == width - 1 || y == 0 || y == height - 1)
                    blurred.setRGB(x, y, buffer.getRGB(x, y));
                else {
                    int sumR = 0;
                    int sumG = 0;
                    int sumB = 0;
                    for (int p = -1; p <= 1; p++)
                        for (int q = -1; q <= 1; q++) {
                            int rgb = buffer.getRGB(x + p, y + q);
                            sumR += (rgb >> 16) & 0xFF;
                            sumG += (rgb >> 8) & 0xFF;
                            sumB += rgb & 0xFF;
                        }
                    blurred.setRGB(x, y, 0xFF << 24 | sumR / 9 << 16 | sumG / 9 << 8 | sumB / 9);
                }
            }

        buffer = blurred;

        repaint();
    }

    //mouse listener implementation

    private boolean down = false;
    private int x0;
    private int y0;
    private int x1;
    private int y1;

    public void mouseClicked(MouseEvent e) {
        //do nothing
    }

    public void mousePressed(MouseEvent e) {
        if (!SwingUtilities.isLeftMouseButton(e))
            return;
        x0 = e.getX();
        y0 = e.getY();
        x1 = x0;
        y1 = y0;
        down = true;
    }

    public void mouseReleased(MouseEvent e) {
        if (!SwingUtilities.isLeftMouseButton(e))
            return;

        down = false;

        double oldX = coordinates.getX0();
        double oldY = coordinates.getY0();
        double oldM = coordinates.getM();

        setCoordinates(
                new Coordinates(
                        oldX + oldM * Math.min(x0, x1),
                        oldY + oldM * Math.min(y0, y1),
                        oldM * Math.abs(x1 - x0) / getWidth()
                )
        );
    }

    public void mouseEntered(MouseEvent e) {
        //do nothing
    }

    public void mouseExited(MouseEvent e) {
        //do nothing
    }

    public void mouseDragged(MouseEvent e) {
        if (!SwingUtilities.isLeftMouseButton(e))
            return;

        x1 = e.getX();
        y1 = e.getY();
        repaint();
    }

    public void mouseMoved(MouseEvent e) {
        //do nothing
    }
}
